home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
Text⁄Files
/
Writeswell Jr. 1.0.2 Master
/
Writeswell Jr. Source
/
ServiceMgr.c
< prev
next >
Wrap
Text File
|
1992-10-26
|
11KB
|
477 lines
/* ServiceMgr.c
* Handle the Services menu in Writeswell, Jr.
* ©1992 Working Software, Inc.
* This source code is copyrighted. Permission is granted to use the Word Services
* portion of the Writeswell Jr. source code in your own programs, but you
* may not distribute the Writeswell Jr. word-processor code as a
* commercial product. If you modify the code, please do not call it
* Writeswell Jr. (or Writeswell.) This will ensure that people understand the
* program and don’t have to deal with a number of different versions with
* who-knows-what going on in the code.
*
* Writeswell Jr. and Writeswell are trademarks of Working Software, Inc.
* 19 Apr 92 Mike Crawford
*/
#include <Aliases.h>
#include <EPPC.h>
#include <AppleEvents.h>
#include <AEObjects.h>
#include <AEPackObject.h>
#include "AERegistry.h"
#include "WordServices.h"
#include "TestBed.h"
#include "TBConstants.h"
#include "AppEvents.h"
#include "AEObj.h"
#include "Gripe.h"
#include "Prefs.h"
#include "DoChecking.h"
#include "ObText.h"
#include "InitMenu.h"
#include "ServiceMgr.h"
#include "TBGlobals.h"
OSErr GetNewBatchService( void )
{
AEAddressDesc spellerAddr;
AEDesc stringDesc;
AEDesc aliasDesc;
AEDesc iconDesc;
OSErr err;
if ( CountServices() >= kMaxServices ){
RealGripe( "\pNo more services may be added" );
return noErr;
}
/* Look for a currently running speller */
err = GetSpellerAddress( &spellerAddr );
if ( err ){
return ( err == userCanceledErr ? noErr : err );
}
/*****
* Request the speller's batch menu string
*****/
err = GetAppProperty( &spellerAddr, pBatchMenuString, typePString, &stringDesc );
if ( err ){
Gripe( "\pGetAppProperty failed to get menu string" );
return err;
}
/*DebugStr( *(stringDesc.dataHandle) );*/ /* Uncomment this to look at string */
/*****
* Request the speller's location alias
*****/
err = GetAppProperty( &spellerAddr, pLocation, typeAlias, &aliasDesc );
if ( err ){
Gripe( "\pGetAppProperty failed to get location alias" );
return err;
}
/*
pMenuIcon
Description: The value of this property is a small icon that may be
placed in the menu along with the interactive or batch
menu strings. It should be identical to the small icon
that the speller shows in the Finder. Word processors that
take advantage of this can use it to make the different menu
items more distinguishable (a user might have two different
spelling checkers).
Object Class ID: typePixelMap
*/
iconDesc.dataHandle = (Handle)NULL;
iconDesc.descriptorType = typeNull;
err = GetAppProperty( &spellerAddr, pMenuIcon, typeSmallIcon, &iconDesc );
/* It is permissible for the icon not to be present. We just won't display one.
*/
if ( err && err != errAENoSuchObject ){
Gripe( "\pGetAppProperty failed to get speller menu icon" );
return err;
}
/* Save the information in the preferences file */
err = SaveServiceInfo( kBatchService, stringDesc, aliasDesc, iconDesc );
if ( err ){
Gripe( "\pCould not save service info" );
return err;
}
RebuildServiceMenu();
err = AEDisposeDesc( &stringDesc );
if ( err ){
Gripe( "\pAEDisposeDesc failed" );
return err;
}
err = AEDisposeDesc( &aliasDesc );
if ( err ){
Gripe( "\pAEDisposeDesc failed" );
return err;
}
err = AEDisposeDesc( &iconDesc );
if ( err ){
Gripe( "\pAEDisposeDesc failed" );
return err;
}
err = AEDisposeDesc( &spellerAddr );
if ( err ){
Gripe( "\pAEDisposeDesc failed" );
return err;
}
spellerAddr.descriptorType = typeNull;
spellerAddr.dataHandle = (Handle)NULL;
return noErr;
}
OSErr GetAppProperty( AEAddressDesc *spellerAddrPtr,
DescType propCode,
DescType desiredType,
AEDesc *resultPtr )
{
AEDesc errDesc;
AppleEvent getDataEvent;
AppleEvent replyEvent;
AEDesc nullDesc;
AEDesc propSpec;
AEDesc propDesc;
OSErr err;
/* Create the descriptor for the container (the application, or null) */
err = AECreateDesc( typeNull, (Ptr)NULL, (Size)0, &nullDesc );
if ( err )
return err;
/* Create the key data, which gives the code for the desired property */
err = AECreateDesc( typeType, (Ptr)&propCode, sizeof( propCode ), &propDesc );
if ( err )
return err;
/* Create the Object Specifier for the menu string property */
err = CreateObjSpecifier( typeProperty,
&nullDesc,
formPropertyID,
&propDesc,
true, /* Dispose of input descriptors */
&propSpec );
if ( err )
return err;
/* Create the event to send to the speller */
err = AECreateAppleEvent( kAECoreSuite,
kAEGetData,
spellerAddrPtr,
kAutoGenerateReturnID,
kAnyTransactionID,
&getDataEvent );
if ( err ){
Gripe( "\pcreate getd event failed" );
return err;
}
/* Insert the object specifier as the direct object of the batch event */
err = AEPutParamDesc( &getDataEvent,
keyDirectObject,
&propSpec );
if ( err ){
Gripe( "\pAEPutParamDesc failed to put direct object on Get Data event" );
return err;
}
err = AEDisposeDesc( &propSpec );
if ( err ){
Gripe( "\pAEDisposeDesc failed" );
return err;
}
/* Send the event. We await the reply, so that if there is a failure of some
* sort in the initial connection, we can alert the user right away. The timeout
* value to use here should be as long as one would care to have a user wait for
* the completion of a menu command. Since we expect that the speller is on a local
* machine in this case, and should be able to respond immediately, we just give
* a few seconds for the timeout.
*
* We should assign an idle proc to spin the cursor. Even better would be a progress
* dialog that says "Contacting speller" or some such, with an animated display that
* shows the time elapsed relative to the total timeout, so the user will know how
* long she may have to wait
*/
#define kFewSeconds 300
err = AESend( &getDataEvent,
&replyEvent,
kAEWaitReply + kAENeverInteract,
kAENormalPriority,
kFewSeconds,
(IdleProcPtr)NULL,
(EventFilterProcPtr)NULL );
if ( err ){
Gripe( "\psend getd event failed" );
return err;
}
err = AEDisposeDesc( &getDataEvent );
if ( err ){
Gripe( "\pAEDisposeDesc failed" );
return err;
}
/* At this point we have received the client's reply event. Check for an error
* result.
*/
err = AEGetParamDesc( &replyEvent,
keyErrorNumber,
typeShortInteger,
&errDesc );
if ( err == errAEDescNotFound ){
/* There is no error value - get the data from the reply event.
* This will call our coercion routine to convert the text to a Pascal string -
* the data is actually either typeIntlText or typeChar.
*/
err = AEGetParamDesc( &replyEvent,
keyDirectObject,
desiredType,
resultPtr );
if ( err ){
Gripe( "\pCannot get reply value" );
return err;
}
} else {
err = AEDisposeDesc( &replyEvent );
if ( err ){
Gripe( "\pAEDisposeDesc failed" );
return;
}
err = **(short**)(errDesc.dataHandle);
/* err = */ AEDisposeDesc( &propSpec );
if ( err ){
if ( err == errAENoSuchObject )
return err; /* This is an OK error */
else{
Gripe( "\pError result returned from speller" );
return err;
}
}
}
return noErr;
}
void RebuildServiceMenu( void )
{
MenuHandle servMenu;
short numItems;
short i;
servMenu = GetServiceMenu();
if ( !servMenu ){
Gripe( "\pCannot get service menu handle" );
return;
}
numItems = CountMItems( servMenu );
for ( i = numItems; i > kSMDash; i-- ){
DelMenuItem( servMenu, i );
}
BuildServiceMenu();
return;
}
OSErr GetSpellerAddress( AEAddressDesc *spellerAddrPtr )
{
PortInfoRec portInfo;
TargetID targetID;
OSErr err;
AEAddressDesc spellerAddr;
err = GetTargetAddress( (StringPtr)"\pChoose a Word Services Server",
(StringPtr)"\pApple Event Aware Programs",
&portInfo,
spellerAddrPtr,
(StringPtr)"\pWORDSERVICES",
&targetID );
return err;
}
short CountServices( void )
{
WWJrPrefsHdl prefHdl;
short i;
short count;
prefHdl = GetPrefHandle();
if ( !prefHdl ){
Gripe( "\pCannot get preferences handle" );
return kMaxServices;
}
count = 0;
for ( i = 0; i < kMaxServices; i++ ){
if ( (*prefHdl)->serviceType[ i ] != kNoService )
count++;
}
return count;
}
short GetServiceSlot( void )
{
WWJrPrefsHdl prefHdl;
short i;
prefHdl = GetPrefHandle();
if ( !prefHdl ){
Gripe( "\pCannot get preferences handle" );
return kMaxServices;
}
for ( i = 0; i < kMaxServices; i++ ){
if ( (*prefHdl)->serviceType[ i ] == kNoService )
return i;
}
return kMaxServices; /* No Free slots */
}
OSErr SaveServiceInfo( ServiceType serviceType,
AEDesc menuDesc,
AEDesc aliasDesc,
AEDesc iconDesc )
{
short slot;
WWJrPrefsHdl prefHdl;
short resID;
short iconResID;
Handle resHandle;
short curFile;
OSErr err;
slot = GetServiceSlot();
if ( slot == kMaxServices ){
Gripe( "\pOut of slots for new services" );
return ioErr; /* Not sure what a good error would be */
}
prefHdl = GetPrefHandle();
if ( !prefHdl ){
Gripe( "\pCannot get preferences handle" );
return resNotFound;
}
resID = kServiceBaseID + slot;
curFile = CurResFile();
UseResFile( gPrefFileRefNum );
/* Make sure there's no old resources around... there shouldn't be */
resHandle = GetResource( 'STR ', resID );
if ( resHandle )
RmveResource( resHandle );
resHandle = GetResource( rAliasType, resID );
if ( resHandle )
RmveResource( resHandle );
/* Copy the string into the resource file */
resHandle = menuDesc.dataHandle;
err = HandToHand( &resHandle );
if ( err ){
UseResFile( curFile );
return err;
}
AddResource( resHandle, 'STR ', resID, "\p" );
err = ResError();
if ( err ){
DisposHandle( resHandle );
UseResFile( curFile );
return err;
}
WriteResource( resHandle );
/* Copy the alias record into the resource file */
resHandle = aliasDesc.dataHandle;
err = HandToHand( &resHandle );
if ( err ){
UseResFile( curFile );
return err;
}
AddResource( resHandle, rAliasType, resID, "\p" ); /* rAliasType is 'alis' */
err = ResError();
if ( err ){
DisposHandle( resHandle );
UseResFile( curFile );
return err;
}
WriteResource( resHandle );
/* Copy the menu icon into the resource file */
resHandle = iconDesc.dataHandle;
if ( iconDesc.descriptorType != typeNull && resHandle != (Handle)NULL ){
err = HandToHand( &resHandle );
if ( err ){
UseResFile( curFile );
return err;
}
iconResID = kMenuIconBaseID + slot;
AddResource( resHandle, 'SICN', iconResID, "\p" );
err = ResError();
if ( err ){
DisposHandle( resHandle );
UseResFile( curFile );
return err;
}
WriteResource( resHandle );
}
(*prefHdl)->serviceType[ slot ] = serviceType;
ChangedResource( prefHdl );
WriteResource( prefHdl );
UseResFile( curFile );
return noErr;
}